/*
 * ArchivoDeBloques.cpp
 *
 */

#include "ArchivoDeBloques.h"

ArchivoDeBloques::ArchivoDeBloques(string nombreArch) {

	this->nombreArch = nombreArch;
	unsigned int tamDeBloque;
	unsigned int cantDeBloques;

	std::ifstream archivo(nombreArch.c_str(), std::ios::binary);
	archivo.read(reinterpret_cast<char*>(&tamDeBloque), sizeof(unsigned int));
	archivo.read(reinterpret_cast<char*>(&cantDeBloques), sizeof(unsigned int));
	archivo.close();

	this->tamBloque = tamDeBloque;
	this->cantBloques = cantDeBloques;

}

ArchivoDeBloques::ArchivoDeBloques(string nombreArch, unsigned int tamBloque) {
	this->nombreArch = nombreArch;
	this->tamBloque = tamBloque;

	ofstream archivo;

	unsigned int cantbloques = 0;
	this->cantBloques = 0;

	archivo.open(nombreArch.c_str(), ios::binary);
	archivo.write(reinterpret_cast<const char *>(&tamBloque),
			sizeof(unsigned int));
	archivo.write(reinterpret_cast<const char *>(&cantbloques),
			sizeof(unsigned int));
	archivo.close();
}

ArchivoDeBloques::~ArchivoDeBloques() {

}


ArchivoDeBloques::ArchivoDeBloques(string nombreArch, unsigned int cantBloques,
		unsigned int tamBloque) {

	this->nombreArch = nombreArch;
	this->tamBloque = tamBloque;
	//Se setea en 0 porque despues se agregan los bloques.
	this->cantBloques = 0;

	ofstream archivo;

	archivo.open(nombreArch.c_str(), ios::binary);
	archivo.write(reinterpret_cast<const char *>(&tamBloque),
			sizeof(unsigned int));
	archivo.write(reinterpret_cast<const char *>(&cantBloques),
			sizeof(unsigned int));
	archivo.close();

	agregarBloquesVacios(cantBloques);
}

int ArchivoDeBloques::agregarBloquesVacios(unsigned int cantBloques) {
	ofstream archivo;

	//Lo abre y agrega al final
	archivo.open(this->nombreArch.c_str(), ios::binary | ios::app);

	char* buffer = new char[cantBloques * tamBloque];
	archivo.write(buffer, (cantBloques * tamBloque));

	delete[] buffer;
	archivo.close();

	actualizarCantBloques(this->cantBloques+cantBloques);

	return 0;
}

int ArchivoDeBloques::escribirBloque(Bloque bloque, unsigned int numeroBloque) {
	ofstream archivo;

	archivo.open(this->nombreArch.c_str(), ios::binary | ios::in);
	archivo.seekp((this->tamBloque * numeroBloque)+8, ios::beg);
	archivo.write(bloque.bufferBloque.c_str(), bloque.tamBloque);
	archivo.close();

	//actualizarCantBloques(this->cantBloques+1);

	return 0;
}

int ArchivoDeBloques::escribirBloque(Bloque bloque) {
	ofstream archivo;

	//Lo abre y agrega al final
	archivo.open(this->nombreArch.c_str(), ios::binary | ios::app);
	archivo.write(bloque.bufferBloque.c_str(), bloque.tamBloque);
	archivo.close();

	actualizarCantBloques(this->cantBloques+1);

	return 0;
}

int ArchivoDeBloques::escribirRegistro(Registro registro,
		unsigned int numeroBloque) {

	Bloque* bloqueLeido = leerBloque(numeroBloque);
	int res = (*bloqueLeido).agregarRegistro(registro);
	if (res!=-1){
		escribirBloque((*bloqueLeido),numeroBloque);
	}
	return 0;
}


Bloque* ArchivoDeBloques::leerBloque(unsigned int numeroBloque) {

	char* bufferBloque = new char [this->tamBloque];
	bufferBloque [this->tamBloque] = 0;
	ifstream archivo(this->nombreArch.c_str(), ios::in | ios::binary);

	archivo.seekg((this->tamBloque * numeroBloque)+8, ios::beg);
	archivo.read(bufferBloque, this->tamBloque);

	Bloque* bloqueleido= new Bloque(tamBloque);
	(*bloqueleido).bufferBloque=bufferBloque;
	archivo.close();
	return bloqueleido;

}

Registro* ArchivoDeBloques::leerRegistro(unsigned int numeroBloque,
		unsigned int numeroRegistro) {

	Bloque* bloquePedido = this->leerBloque(numeroBloque);
	Registro* registroPedido = (*bloquePedido).obtenerRegistro(numeroRegistro);
	return registroPedido;
}

unsigned int ArchivoDeBloques::actualizarCantBloques(unsigned int cantidad) {
	ofstream archivo;

	archivo.open(this->nombreArch.c_str(), ios::binary | ios::in);
	archivo.seekp(4, ios::beg);

	archivo.write(reinterpret_cast<const char *>(&cantidad),
			sizeof(unsigned int));
	this->cantBloques = cantidad;
	archivo.close();
}

